﻿// --- Copyright (c) 2010 Steven Hartgers ---
// Copyright (C) 2010 Steven Hartgers All rights are reserved.
// Author contact: fiinix00/at\gmail.com
// ------------------------------------------------------------------------
// This program is free software: you can redistribute it and/or modify 
// it under the terms of the GNU General Public License as published by 
// the Free Software Foundation, either version 3 of the License, or 
// (at your option) any later version. 
//  
// This program is distributed in the hope that it will be useful, 
// but WITHOUT ANY WARRANTY; without even the implied warranty of 
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
// GNU General Public License for more detail
//  
// You should have received a copy of the GNU General Public License 
// along with this program.  If not, see <http://www.gnu.org/licenses/>.
// ------------------------------------------------------------------------
// COPYRIGHT NOTICE: This copyright notice may NOT be removed, obscured or modified 
// without written consent from the author.
// --- End copyright notice --- 


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Collections;
using System.ComponentModel;
using System.Reflection;
using System.Diagnostics;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
using Hack.Conversion;
using System.Collections.Specialized;
using System.Net.Mime;
using System.IO.Compression;
using System.Security.Cryptography;
using System.Web;
using System.Runtime.InteropServices;
using Hack.SystemAPI;
using Microsoft.Win32;
using System.Drawing;
using System.Windows.Forms;
using System.Threading;
using Hack.Attributes;
using NetFx.AGIL;
using NetFx.SMIL;
using System.Drawing.Imaging;
using SMath = System.Math;
using SConsole = System.Console;
using System.Globalization;
using Hack.DataStructures;
using System.Collections.ObjectModel;
using System.Data;
using Hack.Reflection;
using System.Linq.Expressions;
using Hack.Synchronization;
using Hack.Properties;

namespace Hack.Extensions
{
    [Extension]
    public static class StringExtrnsions
    {
        public static IList<string> SortStringLength(this IList<string> stringList)
        {
            string[] strs = stringList.ToArray<string>();
            Array.Sort(strs, new Comparison<string>(delegate(string str1, string str2)
            {
                if (str1 == null && str2 == null)
                    return 0; //both empty
                else if (str1 == null)
                    return -1; //empty string before non-empty string
                else if (str2 == null)
                    return 1; //non-empty string after empty string
                else
                {
                    if (str1.Length < str2.Length)
                        return -1; //shorter string before longer string
                    else if (str1.Length > str2.Length)
                        return 1; //longer string after shorter string
                    else
                        return str1.CompareTo(str2); //alphabetical order
                }
            }));

            return stringList = strs;
        }
        public static bool HasText(this string str)
        {
            return !string.IsNullOrEmpty(str);
        }

        public static string DefaultText(this string str, string defaultText)
        {
            if (str.HasText()) return str;
            else return defaultText;
        }

        public static string AssertHasText(this string str, string errorMessage)
        {
            if (str.HasText())
                return str;
            else
                throw new ArgumentException(errorMessage);
        }

        public static string Add(this string str, string part, string separator)
        {
            if (str.HasText())
            {
                if (part.HasText())
                    return str + separator + part;
                else
                    return str;
            }
            else
                return part;
        }

        public static string AddLine(this string str, string part)
        {
            return Add(str, part, "\r\n");
        }

        public static string[] Lines(this string str)
        {
            if (str.HasText())
                return str.Split(new string[] { "\r\n" }, StringSplitOptions.None);
            else
                return new string[0];
        }

        public static string Left(this string str, int numChars)
        {
            return Left(str, numChars, true);
        }

        public static string Left(this string str, int numChars, bool throws)
        {
            if (numChars > str.Length)
            {
                if (throws)
                    throw new InvalidOperationException(Resources.String0IsTooShort.Formato(str));
                return str;
            }

            return str.Substring(0, numChars);
        }

        public static string Right(this string str, int numChars)
        {
            return Right(str, numChars, true);
        }

        public static string Right(this string str, int numChars, bool throws)
        {
            if (numChars > str.Length)
            {
                if (throws)
                    throw new InvalidOperationException(Resources.String0IsTooShort.Formato(str));
                return str;
            }

            return str.Substring(str.Length - numChars, numChars);
        }

        public static string RemoveLeft(this string str, int numChars)
        {
            return str.RemoveLeft(numChars, true);
        }

        public static string RemoveLeft(this string str, int numChars, bool throws)
        {
            if (numChars > str.Length)
            {
                if (throws)
                    throw new InvalidOperationException(Resources.String0IsTooShort.Formato(str));
                return "";
            }

            return str.Substring(numChars);
        }

        public static string RemoveRight(this string str, int numChars)
        {
            return str.RemoveRight(numChars, true);
        }

        public static string RemoveRight(this string str, int numChars, bool throws)
        {
            if (numChars > str.Length)
            {
                if (throws)
                    throw new InvalidOperationException(Resources.String0IsTooShort.Formato(str));
                return "";
            }

            return str.Substring(0, str.Length - numChars);
        }


        public static string PadChopRight(this string str, int length)
        {
            str = str ?? "";
            return str.Length > length ? str.Substring(0, length) : str.PadRight(length);
        }

        public static string PadChopLeft(this string str, int length)
        {
            str = str ?? "";
            return str.Length > length ? str.Substring(str.Length - length, length) : str.PadLeft(length);
        }

        public static string VerticalEtc(this string str, int maxLines)
        {
            return str.VerticalEtc(maxLines, "(...)");
        }

        public static string VerticalEtc(this string str, int maxLines, string etcString)
        {
            if (str.HasText() && (str.Contains("/r/n")))
            {
                string[] arr = str.Split(new string[] { "/r/n" }, maxLines, StringSplitOptions.None);
                string res = arr.ToString("/r/n");
                if (res.Length < str.Length)
                    res += etcString;
                str = res;
            }
            return str;
        }


        public static string Etc(this string str, int max, string etcString)
        {
            if (str.HasText() && (str.Length > max))
                return str.Left(max - (etcString.HasText() ? etcString.Length : 0)) + etcString;
            return str;
        }

        public static string Etc(this string str, int max)
        {
            return str.Etc(max, "(...)");
        }

        public static string RemoveChars(this string str, params char[] chars)
        {
            StringBuilder sb = new StringBuilder(str.Length);
            for (int i = 0; i < str.Length; i++)
            {
                if (!chars.Contains(str[i]))
                    sb.Append(str[i]);
            }
            return sb.ToString();
        }


        public static string Formato(string format, object arg0)
        {
            return string.Format(format, arg0);
        }

        public static string Formato(string format, object arg0, object arg1)
        {
            return string.Format(format, arg0, arg1);
        }

        public static string Formato(string format, object arg0, object arg1, object arg2)
        {
            return string.Format(format, arg0, arg1, arg2);
        }

        public static string Formato(this string pattern, params object[] parameters)
        {
            return string.Format(pattern, parameters);
        }

        public static string Formato(this string format, IFormatProvider provider, params object[] args)
        {
            return string.Format(provider, format, args);
        }

        public static string Replace(this string str, Dictionary<string, string> replacements)
        {
            Regex regex = new Regex(replacements.Keys.ToString(a => "(" + Regex.Escape(a) + ")", "|"));

            return regex.Replace(str, m => replacements[m.Value]);
        }

        public static string Indent(this string str, int numChars)
        {
            return Indent(str, numChars, ' ');
        }

        public static string Indent(this string str, int numChars, char indentChar)
        {
            string space = new string(indentChar, numChars);
            StringBuilder sb = new StringBuilder();
            using (StringReader sr = new StringReader(str))
            {
                for (string line = sr.ReadLine(); line != null; line = sr.ReadLine())
                {
                    sb.Append(space);
                    sb.AppendLine(line);
                }
            }

            string result = sb.ToString(0, str.EndsWith("\r\n") ? sb.Length : SMath.Max(sb.Length - 2, 0));

            return result;
        }

        public static string SpacePascal(this string pascalStr, bool preserveUppercase)
        {
            StringBuilder sb = new StringBuilder();
            for (int i = 0; i < pascalStr.Length; i++)
            {
                char a = pascalStr[i];
                if (char.IsUpper(a) && i + 1 < pascalStr.Length && !char.IsUpper(pascalStr[i + 1]))
                {
                    if (sb.Length > 0)
                        sb.Append(' ');
                    sb.Append(preserveUppercase ? a : char.ToLower(a));
                }
                else
                    sb.Append(a);

            }

            return sb.ToString();
        }

        public static string FirstUpper(this string str)
        {
            if (str.HasText())
                return char.ToUpper(str[0]) + str.Substring(1);
            return str;
        }

        public static string Replicate(this string str, int times)
        {
            if (times < 0)
                throw new ArgumentException("times");

            StringBuilder sb = new StringBuilder(str.Length * times);
            for (int i = 0; i < times; i++)
                sb.Append(str);
            return sb.ToString();
        }
        public static int? ToInt(this string str)
        {
            int result;
            if (int.TryParse(str, out result))
                return result;
            else
                return null;
        }

        public static long? ToLong(this string str)
        {
            long result;
            if (long.TryParse(str, out result))
                return result;
            else
                return null;
        }

        public static short? ToShort(this string str)
        {
            short result;
            if (short.TryParse(str, out result))
                return result;
            else
                return null;
        }

        public static float? ToFloat(this string str)
        {
            float result;
            if (float.TryParse(str, out result))
                return result;
            else
                return null;
        }

        public static double? ToDouble(this string str)
        {
            double result;
            if (double.TryParse(str, out result))
                return result;
            else
                return null;
        }

        public static decimal? ToDecimal(this string str)
        {
            decimal result;
            if (decimal.TryParse(str, out result))
                return result;
            else
                return null;
        }

        public static int ToInt(this string str, string error)
        {
            int result;
            if (int.TryParse(str, out result))
                return result;

            throw new FormatException(error);
        }

        public static long ToLong(this string str, string error)
        {
            long result;
            if (long.TryParse(str, out result))
                return result;

            throw new FormatException(error);
        }

        public static short ToShort(this string str, string error)
        {
            short result;
            if (short.TryParse(str, out result))
                return result;

            throw new FormatException(error);
        }


        public static float? ToFloat(this string str, string error)
        {
            float result;
            if (float.TryParse(str, out result))
                return result;

            throw new FormatException(error);
        }

        public static double ToDouble(this string str, string error)
        {
            double result;
            if (double.TryParse(str, out result))
                return result;

            throw new FormatException(error);
        }

        public static decimal ToDecimal(this string str, string error)
        {
            decimal result;
            if (decimal.TryParse(str, out result))
                return result;

            throw new FormatException(error);
        }


        /// <summary>
        /// Searches for URL's eg: http://google.com/
        /// </summary>
        /// <param name="rawCode"></param>
        /// <returns></returns>
        public static List<string> ExtractLinks(this string rawCode)
        {
            List<string> links = new List<string>();

            string startSquence = "<a href=\"";
            string endSequence = "\"";

            rawCode = rawCode.ToLower();

            while (rawCode.IndexOf("<a href") != -1)
            {
                int start = rawCode.IndexOf(startSquence) + startSquence.Length;
                int end = rawCode.IndexOf(endSequence, start);

                //Extract the link, and add it to the list
                if (end > start)
                {
                    string link = rawCode.Substring(start, end - start);

                    if (link != string.Empty)
                    {
                        if (!link.StartsWith("http://"))
                        {
                            //It's a relative link, add a ..
                            link = "../" + link;
                        }

                        links.Add(link);
                    }
                }

                //Trim the raw data
                rawCode = rawCode.Substring(end + endSequence.Length);
            }

            return links;
        }
        /// <summary>
        /// Makes a untrustable string clean and secure before inserting to xml file
        /// </summary>
        /// <param name="text"></param>
        /// <returns></returns>
        public static string XmlEncode(this string text)
        {
            if (text == null) return String.Empty;

            StringBuilder sb = new StringBuilder();
            foreach (char ch in text)
            {
                if (ch == '<') sb.Append("&lt;");
                else if (ch == '\'' || ch == '\"' || ch == '\r' || ch == '\n')
                    sb.AppendFormat("&#{0};", (int)ch);
                else
                    sb.Append(ch);
            }
            return text = sb.ToString();
        }
        /// <summary>
        /// Makes all Uppercase chars to lower and lower to upper
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public static string SwapCases(this string input)
        {
            string ret = "";
            for (int i = 0; i < input.Length; i++)
            {
                if (string.Compare(input.Substring(i, 1), input.Substring(i, 1).ToUpper(), false) == 0)
                    ret += input.Substring(i, 1).ToLower();
                else
                    ret += input.Substring(i, 1).ToUpper();
            }
            return input = ret;
        }
        public static string AlternateCases(this string input, bool firstIsUpper)
        {
            string ret = "";
            for (int i = 0; i < input.Length; i++)
            {
                if (firstIsUpper)
                    ret += input.Substring(i, 1).ToUpper();
                else
                    ret += input.Substring(i, 1).ToLower();

                firstIsUpper = !firstIsUpper;
            }

            return input = ret;
        }
        /// <summary>
        /// Removes [ a-e-i-o-u ] - Keeps [ a-z ]
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public static string RemoveVowels(this string input)
        {
            string ret = "";
            string currentLetter;
            for (int i = 0; i < input.Length; i++)
            {
                currentLetter = input.Substring(i, 1);

                if (string.Compare(currentLetter, "a", true) != 0 &&
                    string.Compare(currentLetter, "e", true) != 0 &&
                    string.Compare(currentLetter, "i", true) != 0 &&
                    string.Compare(currentLetter, "o", true) != 0 &&
                    string.Compare(currentLetter, "u", true) != 0)
                {
                    //Not a vowel, add it
                    ret += currentLetter;
                }
            }
            return input = ret;
        }
        /// <summary>
        /// Removes [ a-z ] - Keeps [ a-e-i-o-u ]
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public static string KeepVowels(string input)
        {
            string ret = "";
            string currentLetter;
            for (int i = 0; i < input.Length; i++)
            {
                currentLetter = input.Substring(i, 1);

                if (string.Compare(currentLetter, "a", true) == 0 ||
                    string.Compare(currentLetter, "e", true) == 0 ||
                    string.Compare(currentLetter, "i", true) == 0 ||
                    string.Compare(currentLetter, "o", true) == 0 ||
                    string.Compare(currentLetter, "u", true) == 0)
                {
                    //A vowel, add it
                    ret += currentLetter;
                }
            }
            return input = ret;
        }
        /// <summary>
        /// Makes a array to a string, forces a ToString() on all objects and returns
        /// </summary>
        /// <param name="input"></param>
        /// <param name="separator"></param>
        /// <returns></returns>
        public static string ArrayToString(this Array input, string separator)
        {
            string ret = "";
            for (int i = 0; i < input.Length; i++)
            {
                ret += input.GetValue(i).ToString();
                if (i != input.Length - 1)
                    ret += separator;
            }
            return ret;
        }
        /// <summary>
        /// Inserts a [param separator] betwen all words
        /// </summary>
        /// <param name="input"></param>
        /// <param name="separator"></param>
        /// <returns></returns>
        public static string InsertSeparator(this string input, string separator)
        {
            string ret = "";
            for (int i = 0; i < input.Length; i++)
            {
                ret += input.Substring(i, 1);
                if (i != input.Length - 1)
                    ret += separator;
            }
            return input = ret;
        }
        /// <summary>
        /// Inserts a [param separator] every [param count] char
        /// </summary>
        /// <param name="input"></param>
        /// <param name="separator"></param>
        /// <returns></returns>
        public static string InsertSeparatorEvery(this string input, string separator, int count)
        {
            string ret = "";
            for (int i = 0; i < input.Length; i++)
            {
                if (i + count < input.Length)
                    ret += input.Substring(i, count);
                else
                    ret += input.Substring(i);

                if (i != input.Length - 1)
                    ret += separator;
            }
            return input = ret;
        }
        /// <summary>
        /// "Hello" -> true
        /// "hello" -> false
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public static bool IsCapitalized(this string input)
        {
            if (input.Length == 0) return false;
            return string.Compare(input.Substring(0, 1), input.Substring(0, 1).ToUpper(), false) == 0;
        }
        /// <summary>
        /// "Hello" -> false
        /// "hello" -> true
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public static bool IsLowerCase(this string input)
        {
            for (int i = 0; i < input.Length; i++)
            {
                if (string.Compare(input.Substring(i, 1), input.Substring(i, 1).ToLower(), false) != 0)
                    return false;
            }
            return true;
        }
        /// <summary>
        /// "Hello" -> true
        /// "hello" -> false
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public static bool IsUpperCase(this string input)
        {
            for (int i = 0; i < input.Length; i++)
            {
                if (string.Compare(input.Substring(i, 1), input.Substring(i, 1).ToUpper(), false) != 0)
                    return false;
            }
            return true;
        }
        /// <summary>
        /// Counts all [param chars] in [param input]
        /// </summary>
        /// <param name="input"></param>
        /// <param name="chars"></param>
        /// <param name="ignoreCases"></param>
        /// <returns></returns>
        public static int CountTotal(this string input, string chars, bool ignoreCases)
        {
            int count = 0;
            for (int i = 0; i < input.Length; i++)
            {
                if (!(i + chars.Length > input.Length) &&
                    string.Compare(input.Substring(i, chars.Length), chars, ignoreCases) == 0)
                {
                    count++;
                }
            }
            return count;
        }
        /// <summary>
        /// Return true if [param input] contains one of the vowels [ a-e-i-o-u ]
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public static bool HasVowels(this string input)
        {
            string currentLetter;
            for (int i = 0; i < input.Length; i++)
            {
                currentLetter = input.Substring(i, 1);

                if (string.Compare(currentLetter, "a", true) == 0 ||
                  string.Compare(currentLetter, "e", true) == 0 ||
                  string.Compare(currentLetter, "i", true) == 0 ||
                  string.Compare(currentLetter, "o", true) == 0 ||
                  string.Compare(currentLetter, "u", true) == 0)
                {
                    //A vowel found
                    return true;
                }
            }

            return false;
        }
        /// <summary>
        /// True if the [param input] only contains " "(spaces)
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public static bool IsSpaces(this string input)
        {
            if (input.Length == 0) return false;
            return input.Replace(" ", "").Length == 0;
        }
        /// <summary>
        /// Checks all chars in the word are equal -> true
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public static bool IsRepeatedChar(this string input)
        {
            if (input.Length == 0) return false;
            return input.Replace(input.Substring(0, 1), "").Length == 0;
        }
        /// <summary>
        /// Contains only Numeric chars
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public static bool IsNumeric(this string input)
        {
            for (int i = 0; i < input.Length; i++)
            {
                if (!(Convert.ToInt32(input[i]) >= 48 && Convert.ToInt32(input[i]) <= 57))
                {
                    //Not integer value
                    return false;
                }
            }
            return true;
        }
        /// <summary>
        /// Checks [param input] for Numeric vales
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public static bool HasNumbers(this string input)
        {
            return System.Text.RegularExpressions.Regex.IsMatch(input, "\\d+");
        }
        /// <summary>
        /// Checks [param input], if it contains Strings and Numerics
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public static bool IsAlphaNumberic(this string input)
        {
            char currentLetter;
            for (int i = 0; i < input.Length; i++)
            {
                currentLetter = input[i];

                if (!(Convert.ToInt32(currentLetter) >= 48 && Convert.ToInt32(currentLetter) <= 57) &&
                    !(Convert.ToInt32(currentLetter) >= 65 && Convert.ToInt32(currentLetter) <= 90) &&
                    !(Convert.ToInt32(currentLetter) >= 97 && Convert.ToInt32(currentLetter) <= 122))
                {
                    //Not a number or a letter
                    return false;
                }
            }
            return true;
        }
        /// <summary>
        /// Checks [param input], if it only contais ASCII
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public static bool isLetters(this string input)
        {
            char currentLetter;
            for (int i = 0; i < input.Length; i++)
            {
                currentLetter = input[i];

                if (!(Convert.ToInt32(currentLetter) >= 65 && Convert.ToInt32(currentLetter) <= 90) &&
                    !(Convert.ToInt32(currentLetter) >= 97 && Convert.ToInt32(currentLetter) <= 122))
                {
                    //Not a letter
                    return false;
                }
            }
            return true;
        }
        /// <summary>
        /// Usefull for names "Bill Gates" -> B.G
        /// </summary>
        /// <param name="input"></param>
        /// <param name="capitalize"></param>
        /// <param name="includeSpace"></param>
        /// <returns></returns>
        public static string GetInitials(this string input, bool capitalize, bool includeSpace)
        {
            string[] words = input.Split(new[] { ' ' });

            for (int i = 0; i < words.Length; i++)
            {
                if (words[i].Length > 0)
                    if (capitalize)
                        words[i] = words[i].Substring(0, 1).ToUpper() + ".";
                    else
                        words[i] = words[i].Substring(0, 1) + ".";
            }

            if (includeSpace)
                return string.Join(" ", words);
            else
                return string.Join("", words);
        }
        public static string ToUpperCamerCase(this string camel)
        {
            return camel = Regex.Replace(camel, @"(\b[a-z]|\B[A-Z])", new
                MatchEvaluator((match) =>
                {
                    char c = match.Captures[0].Value[0];
                    return ((c >= 'a') && (c <= 'z')) ? Char.ToUpper(c).ToString() : " " + c;
                }));
        }
        public static string ToLowerCamerCase(this string camel)
        {
            return camel = Regex.Replace(camel, @"(\b[a-z]|\B[A-Z])", new
                MatchEvaluator((match) =>
                {
                    char c = match.Captures[0].Value[0];
                    return ((c >= 'a') && (c <= 'z')) ? Char.ToLower(c).ToString() : " " + c;
                }));
        }
        /// <summary>
        /// Checks all first chars in words in [param input], if all ar uppercase
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public static bool IsTitle(this string input)
        {
            string[] words = input.Split(new char[] { ' ' });

            for (int i = 0; i < words.Length; i++)
            {
                if (words[i].Length > 0)
                    if (string.Compare(words[i].Substring(0, 1).ToUpper(), words[i].Substring(0, 1), false) != 0)
                        return false;
            }
            return true;
        }
        /// <summary>
        /// Checks if the password is a unike password algorytm
        /// 100 = Max
        /// 0 = Min
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        [OrginalAuthor(Author = "D. Rijmenants")]
        public static int PasswordStrength(this string input)
        {
            double total = 0;
            bool hasUpperCase = false;
            bool hasLowerCase = false;

            total = input.Length * 3;

            char currentLetter;
            for (int i = 0; i < input.Length; i++)
            {
                currentLetter = input[i];
                if (Convert.ToInt32(currentLetter) >= 65 && Convert.ToInt32(currentLetter) <= 92)
                    hasUpperCase = true;

                if (Convert.ToInt32(currentLetter) >= 97 && Convert.ToInt32(currentLetter) <= 122)
                    hasLowerCase = true;
            }

            if (hasUpperCase && hasLowerCase) total *= 1.2;

            for (int i = 0; i < input.Length; i++)
            {
                currentLetter = input[i];
                if (Convert.ToInt32(currentLetter) >= 48 && Convert.ToInt32(currentLetter) <= 57) //Numbers
                    if (hasUpperCase && hasLowerCase) total *= 1.4;
            }

            for (int i = 0; i < input.Length; i++)
            {
                currentLetter = input[i];
                if ((Convert.ToInt32(currentLetter) <= 47 && Convert.ToInt32(currentLetter) >= 123) ||
                    (Convert.ToInt32(currentLetter) >= 58 && Convert.ToInt32(currentLetter) <= 64)) //symbols
                {
                    total *= 1.5;
                    break;
                }
            }

            if (total > 100.0) total = 100.0;

            return (int)total;
        }
        /// <summary>
        /// finds all quotes "A nice day!" -> { A, Nice, Day }
        /// </summary>
        /// <param name="input"></param>
        /// <param name="ignoreQuotes"></param>
        /// <param name="separator"></param>
        /// <returns></returns>
        public static string[] SplitQuotes(this string input, bool ignoreQuotes, string separator)
        {
            if (ignoreQuotes)
                return input.Split(separator.ToCharArray());
            else
            {
                string[] words = input.Split(separator.ToCharArray());
                List<string> newWords = new List<string>();

                for (int i = 0; i < words.Length; i++)
                {
                    if (words[i].StartsWith('"'.ToString()))
                    {
                        List<string> linked = new List<string>();
                        for (int y = i; y < words.Length; y++)
                        {
                            if (words[y].EndsWith('"'.ToString()))
                            {
                                linked.Add(words[y].Substring(0, words[y].Length - 1));
                                i = y;
                                break;
                            }
                            else
                            {
                                if (words[y].StartsWith('"'.ToString()))
                                    linked.Add(words[y].Substring(1));
                            }
                        }
                        newWords.Add(string.Join(separator, linked.ToArray()));
                        linked.Clear();
                    }
                    else
                        newWords.Add(words[i]);
                }
                return newWords.ToArray();
            }
        }
        /// <summary>
        /// Crops a string with a start and end, "Car at the House" { 3,8 } -> " at t"
        /// </summary>
        /// <param name="input"></param>
        /// <param name="start"></param>
        /// <param name="end"></param>
        /// <returns></returns>
        public static string SubstringEnd(this string input, int start, int end)
        {
            if (start > end) //Flip the values
            {
                start ^= end;
                end = start ^ end;
                start ^= end;
            }

            if (end > input.Length) end = input.Length; //avoid errors

            return input.Substring(start, end - start);

        }
        /// <summary>
        /// Get all indexes for a specified word
        /// </summary>
        /// <param name="input"></param>
        /// <param name="chars"></param>
        /// <returns></returns>
        public static int[] IndexOfAll(this string input, string chars)
        {
            List<int> indices = new List<int>();
            for (int i = 0; i < input.Length; i++)
            {
                if (input.Substring(i, 1) == chars)
                    indices.Add(i);
            }

            if (indices.Count == 0)
                indices.Add(-1);

            return indices.ToArray();
        }
        /// <summary>
        /// Usefull for names -> mcjunior -> McJunior, macrowlin -> MacRowlin
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public static string GetNameCasing(this string input)
        {
            string[] words = input.Split(new char[] { ' ' });

            for (int i = 0; i < words.Length; i++)
            {
                if (words[i].Length > 0)
                {
                    words[i] = words[i].Substring(0, 1).ToUpper() + words[i].Substring(1);
                    if (words[i].StartsWith("Mc") && words[i].Length > 2)
                        words[i] = words[i].Substring(0, 2) + words[i].Substring(2, 1).ToUpper() + words[i].Substring(3);
                    else if (words[i].StartsWith("Mac") && words[i].Length > 3)
                        words[i] = words[i].Substring(0, 3) + words[i].Substring(3, 1).ToUpper() + words[i].Substring(4);
                }
            }
            return string.Join(" ", words);
        }
        /// <summary>
        /// Splits at Uppercase char
        /// HelloMyNameIs -> Hello My Name Is
        /// </summary>
        /// <param name="pascalCaseString"></param>
        /// <returns></returns>
        public static string Wordify(this string pascalCaseString)
        {
            var r = new Regex("(?<=[a-z])(?<x>[A-Z])|(?<=.)(?<x>[A-Z])(?=[a-z])");
            return pascalCaseString = r.Replace(pascalCaseString, " ${x}");
        }
        public static string ToTitleCase(this string input)
        {
            return input = Thread.CurrentThread.CurrentCulture.TextInfo.ToTitleCase(input);
        }
        public static string DecapitalizeFirst(this string input)
        {
            return input = new string(input[0], 1) + input.Substring(1, input.Length - 2);
        }
        public static string Append(this string s, string data)
        {
            return s + data;
        }
        public static int WordCount(this String str)
        {
            return str.Split(new char[] { ' ', '.', '?' },
                             StringSplitOptions.RemoveEmptyEntries).Length;
        }
        public static string Reverse(this string s)
        {
            char[] c = s.ToCharArray();
            Array.Reverse(c);
            return new string(c);
        }
        public static string HexString(this byte[] b)
        {
            return HexEncoding.ToString(b);
        }
        public static byte[] HexStringDecode(this string s)
        {
            int i;
            return HexEncoding.GetBytes(s, out i);
        }
        // ReSharper disable InconsistentNaming
        public static string ToASCII(this byte[] b)
        // ReSharper restore InconsistentNaming
        {
            return System.Text.Encoding.ASCII.GetString(b);
        }
        // ReSharper disable InconsistentNaming
        public static char ToASCII(this byte b)
        // ReSharper restore InconsistentNaming
        {
            return (char)System.Text.Encoding.ASCII.GetChars(new byte[] { b })[0];
        }
        public static byte[] ToByte(this string s)
        {
            return System.Text.Encoding.ASCII.GetBytes(s);
        }
        public static byte[] ToByte(this char[] c)
        {
            return System.Text.Encoding.ASCII.GetBytes(c);
        }
        public static byte[] ToByte(this char c)
        {
            return System.Text.Encoding.ASCII.GetBytes(new char[] { c });
        }
        public static string ToBase64(this string s)
        {
            return s.ToByte().ToBase64String();
        }
        public static string FromBase64(this string s)
        {
            return Convert.FromBase64String(s).ToASCII();
        }
        public static bool IsMatch(this string str, string pattern)
        {
            return IsMatch(str, pattern, RegexOptions.None);
        }

        private static Random rand = new Random();
        public static string Permute(this string s, int n)
        {
            char[] c = s.ToCharArray();

            for (int i = 0; i < n; i++)
            {
                int a = rand.Next(s.Length);
                int b = rand.Next(s.Length);
                char t = c[a];
                c[a] = c[b];
                c[b] = t;
            }

            return new string(c);
        }
        public static string Randomize(this string s, int n)
        {
            return Permute(s, n);
        }
        public static bool IsEmailAddress(this string @string)
        {
            //Return false if the string is null
            if (@string == null)
                return false;

            //Build the email pattern
            StringBuilder emailPattern = new StringBuilder(@"^(([^<>()[\]\\.,;:\s@\""]+");
            emailPattern.Append(@"(\.[^<>()[\]\\.,;:\s@\""]+)*)|(\"".+\""))@");
            emailPattern.Append(@"((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}");
            emailPattern.Append(@"\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+");
            emailPattern.Append(@"[a-zA-Z]{2,}))$");

            //Check if the string is valid
            Regex regex = new Regex(emailPattern.ToString());
            return regex.IsMatch(@string);
        }
        public static string Shorten(this string @string, int maxLength)
        {
            //Throw exception if the max length is negative
            if (maxLength < 0)
                throw new ArgumentOutOfRangeException("maxLength", maxLength, "maxLength must be zero or greater");

            //Shorten string if necessary, then return the result
            if (@string.Length > maxLength)
                return @string.Substring(0, maxLength);
            return @string;
        }
        public static string SpaceCapitalLetters(this string @string)
        {
            int i = 1;

            while (i < @string.Length)
            {
                if (Char.IsUpper(@string[i]))
                {
                    if (@string.Length > i + 1 && !Char.IsUpper(@string[i + 1]))
                    {
                        @string = @string.Insert(i, " ");
                        i++;
                    }
                }

                i++;
            }

            return @string;
        }

        #region Match
        public static bool IsMatch(this string str, string pattern, RegexOptions options)
        {
            if (str == null) throw new ArgumentNullException("str");
            if (pattern == null) throw new ArgumentNullException("pattern");
            return Regex.IsMatch(str, pattern, options);
        }
        public static Match Match(this string str, string pattern)
        {
            return Match(str, pattern, RegexOptions.None);
        }
        public static Match Match(this string str, string pattern, RegexOptions options)
        {
            if (str == null) throw new ArgumentNullException("str");
            if (pattern == null) throw new ArgumentNullException("pattern");
            return Regex.Match(str, pattern, options);
        }
        public static IEnumerable<Match> Matches(this string str, string pattern)
        {
            return Matches(str, pattern, RegexOptions.None);
        }
        public static IEnumerable<Match> Matches(this string str, string pattern, RegexOptions options)
        {
            if (str == null) throw new ArgumentNullException("str");
            if (pattern == null) throw new ArgumentNullException("pattern");
            return MatchesImpl(str, pattern, options);
        }
        private static IEnumerable<Match> MatchesImpl(string str, string pattern, RegexOptions options)
        {
            var match = str.Match(pattern, options);
            while (match.Success)
            {
                yield return match;
                match = match.NextMatch();
            }
        }
        #endregion

        #region http://www.wtfdeveloper.com/Default5.aspx
        /// <summary>
        /// Base64 encodes a string.
        /// </summary>
        /// <param name="input">A string</param>
        /// <returns>A base64 encoded string</returns>
        public static string Base64StringEncode(this string input)
        {
            byte[] encbuff = System.Text.Encoding.UTF8.GetBytes(input);
            return Convert.ToBase64String(encbuff);
        }

        /// <summary>
        /// Base64 decodes a string.
        /// </summary>
        /// <param name="input">A base64 encoded string</param>
        /// <returns>A decoded string</returns>
        public static string Base64StringDecode(this string input)
        {
            byte[] decbuff = Convert.FromBase64String(input);
            return System.Text.Encoding.UTF8.GetString(decbuff);
        }

        /// <summary>
        /// A case insenstive replace function.
        /// </summary>
        /// <param name="input">The string to examine.</param>
        /// <param name="newValue">The value to replace.</param>
        /// <param name="oldValue">The new value to be inserted</param>
        /// <returns>A string</returns>
        public static string CaseInsenstiveReplace(this string input,
           string newValue, string oldValue)
        {
            Regex regEx = new Regex(oldValue,
               RegexOptions.IgnoreCase | RegexOptions.Multiline);
            return regEx.Replace(input, newValue);
        }

        /// <summary>
        /// Replaces the first occurence of a string with the replacement value. The Replace
        /// is case senstive
        /// </summary>
        /// <param name="input">The string to examine</param>
        /// <param name="oldValue">The value to replace</param>
        /// <param name="newValue">the new value to be inserted</param>
        /// <returns>A string</returns>
        public static string ReplaceFirst(this string input, string oldValue, string newValue)
        {
            Regex regEx = new Regex(oldValue, RegexOptions.Multiline);
            return regEx.Replace(input, newValue, 1);
        }

        /// <summary>
        /// Replaces the last occurence of a string with the replacement value.
        /// The replace is case senstive.
        /// </summary>
        /// <param name="input">The string to examine</param>
        /// <param name="oldValue">The value to replace</param>
        /// <param name="newValue">the new value to be inserted</param>
        /// <returns>A string</returns>
        public static string ReplaceLast(this string input, string oldValue, string newValue)
        {
            int index = input.LastIndexOf(oldValue);
            if (index < 0)
            {
                return input;
            }
            else
            {
                StringBuilder sb = new StringBuilder(input.Length - oldValue.Length + newValue.Length);
                sb.Append(input.Substring(0, index));
                sb.Append(newValue);
                sb.Append(input.Substring(index + oldValue.Length,
                   input.Length - index - oldValue.Length));

                return sb.ToString();
            }
        }

        /// <summary>
        /// Removes all the words passed in the filter words 
        /// parameters. The replace is NOT case
        /// sensitive.
        /// </summary>
        /// <param name="input">The string to search.</param>
        /// <param name="filterWords">The words to 
        /// repace in the input string.</param>
        /// <returns>A string.</returns>
        public static string FilterWords(this string input,
           params string[] filterWords)
        {
            return input.FilterWords(char.MinValue, filterWords);
        }

        /// <summary>
        /// Removes all the words passed in the filter words 
        /// parameters. The replace is NOT case
        /// sensitive.
        /// </summary>
        /// <param name="input">The string to search.</param>
        /// <param name="mask">A character that is inserted for each 
        /// letter of the replaced word.</param>
        /// <param name="filterWords">The words to 
        // repace in the input string.</param>
        /// <returns>A string.</returns>
        public static string FilterWords(this string input, char mask,
           params string[] filterWords)
        {
            string stringMask = mask == char.MinValue ?
               string.Empty : mask.ToString();
            string totalMask = stringMask;

            foreach (string s in filterWords)
            {
                Regex regEx = new Regex(s,
                   RegexOptions.IgnoreCase | RegexOptions.Multiline);

                if (stringMask.Length > 0)
                {
                    for (int i = 1; i < s.Length; i++)
                        totalMask += stringMask;
                }

                input = regEx.Replace(input, totalMask);

                totalMask = stringMask;
            }

            return input;
        }

        /// <summary>
        /// Checks the passed string to see if has any of the 
        /// passed words. Not case-sensitive.
        /// </summary>
        /// <param name="input">The string to check.</param>
        /// <param name="hasWords">The words to check for.</param>
        /// <returns>A collection of the matched words.</returns>
        public static MatchCollection HasWords(this string input,
           params string[] hasWords)
        {
            StringBuilder sb = new StringBuilder(hasWords.Length + 50);
            //sb.Append("[");

            foreach (string s in hasWords)
            {
                sb.AppendFormat("({0})|", s.Trim().HtmlSpecialEntitiesEncode());
            }

            string pattern = sb.ToString();
            pattern = pattern.TrimEnd('|'); // +"]";

            Regex regEx = new Regex(pattern,
               RegexOptions.IgnoreCase | RegexOptions.Multiline);
            return regEx.Matches(input);
        }

        /// <summary>
        /// A wrapper around HttpUtility.HtmlEncode
        /// </summary>
        /// <param name="input">The string to be encoded</param>
        /// <returns>An encoded string</returns>
        public static string HtmlSpecialEntitiesEncode(this string input)
        {
            return HttpUtility.HtmlEncode(input);
        }

        /// <summary>
        /// A wrapper around HttpUtility.HtmlDecode
        /// </summary>
        /// <param name="input">The string to be decoded</param>
        /// <returns>The decode string</returns>
        public static string HtmlSpecialEntitiesDecode(this string input)
        {
            return HttpUtility.HtmlDecode(input);
        }

        /// <summary>
        /// MD5 encodes the passed string
        /// </summary>
        /// <param name="input">The string to encode.</param>
        /// <returns>An encoded string.</returns>
        public static string MD5String(this string input)
        {
            // Create a new instance of the 
            // MD5CryptoServiceProvider object.
            MD5 md5Hasher = MD5.Create();

            // Convert the input string to a byte 
            // array and compute the hash.
            byte[] data = md5Hasher.ComputeHash(
               Encoding.Default.GetBytes(input));

            // Create a new Stringbuilder to collect the bytes
            // and create a string.
            StringBuilder sBuilder = new StringBuilder();

            // Loop through each byte of the hashed data 
            // and format each one as a hexadecimal string.
            for (int i = 0; i < data.Length; i++)
            {
                sBuilder.Append(data[i].ToString("x2"));
            }

            // Return the hexadecimal string.
            return sBuilder.ToString();
        }

        /// <summary>
        /// Verified a string against the passed MD5 hash.
        /// </summary>
        /// <param name="input">The string to compare.</param>
        /// <param name="hash">The hash to compare against.</param>
        /// <returns>True if the input and the hash 
        /// are the same, false otherwise.</returns>
        public static bool MD5VerifyString(this string input, string hash)
        {
            // Hash the input.
            string hashOfInput = input.MD5String();

            // Create a StringComparer an comare the hashes.
            StringComparer comparer = StringComparer.OrdinalIgnoreCase;

            if (0 == comparer.Compare(hashOfInput, hash))
            {
                return true;
            }
            else
            {
                return false;
            }
        }

        /// <summary>
        /// Left pads the passed input using the HTML 
        /// non-breaking string entity (&nbsp;)
        /// for the total number of spaces.
        /// </summary>
        /// <param name="input">The string to pad.</param>
        /// <param name="totalSpaces">The total number 
        /// to pad the string.</param>
        /// <returns>A padded string.</returns>
        public static string PadLeftHtmlSpaces(this string input,
           int totalSpaces)
        {
            string space = "&nbsp;";
            return input.PadLeft(space, totalSpaces * space.Length);
        }

        /// <summary>
        /// Left pads the passed input using the passed pad string
        /// for the total number of spaces.  It will not 
        /// cut-off the pad even if it 
        /// causes the string to exceed the total width.
        /// </summary>
        /// <param name="input">The string to pad.</param>
        /// <param name="pad">The string to uses as padding.</param>
        /// <param name="totalSpaces">The total number to 
        /// pad the string.</param>
        /// <returns>A padded string.</returns>
        public static string PadLeft(this string input,
           string pad, int totalWidth)
        {
            return input.PadLeft(pad, totalWidth, false);
        }

        /// <summary>
        /// Left pads the passed input using the passed pad string
        /// for the total number of spaces.  It will 
        /// cut-off the pad so that  
        /// the string does not exceed the total width.
        /// </summary>
        /// <param name="input">The string to pad.</param>
        /// <param name="pad">The string to uses as padding.</param>
        /// <param name="totalSpaces">The total number to 
        /// pad the string.</param>
        /// <returns>A padded string.</returns>
        public static string PadLeft(this string input, string pad,
           int totalWidth, bool cutOff)
        {
            if (input.Length >= totalWidth)
                return input;

            int padCount = pad.Length;
            string paddedString = input;

            while (paddedString.Length < totalWidth)
            {
                paddedString += pad;
            }

            // trim the excess.
            if (cutOff)
                paddedString = paddedString.Substring(0, totalWidth);

            return paddedString;
        }

        /// <summary>
        /// Right pads the passed input using the HTML 
        /// non-breaking string entity (&nbsp;)
        /// for the total number of spaces.
        /// </summary>
        /// <param name="input">The string to pad.</param>
        /// <param name="totalSpaces">The total number 
        /// to pad the string.</param>
        /// <returns>A padded string.</returns>
        public static string PadRightHtmlSpaces(this string input,
           int totalSpaces)
        {
            string space = "&nbsp;";
            return input.PadRight(space, totalSpaces * space.Length);
        }

        /// <summary>
        /// Right pads the passed input using the passed pad string
        /// for the total number of spaces.  It will not 
        /// cut-off the pad even if it 
        /// causes the string to exceed the total width.
        /// </summary>
        /// <param name="input">The string to pad.</param>
        /// <param name="pad">The string to uses as padding.</param>
        /// <param name="totalSpaces">The total number to 
        /// pad the string.</param>
        /// <returns>A padded string.</returns>
        public static string PadRight(this string input,
           string pad, int totalWidth)
        {
            return input.PadRight(pad, totalWidth, false);
        }

        /// <summary>
        /// Right pads the passed input using the passed pad string
        /// for the total number of spaces.  It will cut-off
        /// the pad so that  
        /// the string does not exceed the total width.
        /// </summary>
        /// <param name="input">The string to pad.</param>
        /// <param name="pad">The string to uses as padding.</param>
        /// <param name="totalSpaces">The total number to 
        /// pad the string.</param>
        /// <returns>A padded string.</returns>
        public static string PadRight(this string input, string pad,
           int totalWidth, bool cutOff)
        {
            if (input.Length >= totalWidth)
                return input;

            string paddedString = string.Empty;

            while (paddedString.Length < totalWidth - input.Length)
            {
                paddedString += pad;
            }

            // trim the excess.
            if (cutOff)
                paddedString = paddedString.Substring(0,
                   totalWidth - input.Length);

            paddedString += input;

            return paddedString;
        }

        /// <summary>
        /// Removes the new line (\n) and carriage return (\r) symbols.
        /// </summary>
        /// <param name="input">The string to search.</param>
        /// <returns>A string</returns>
        public static string RemoveNewLines(this string input)
        {
            return input.RemoveNewLines(false);
        }

        /// <summary>
        /// Removes the new line (\n) and carriage return 
        /// (\r) symbols.
        /// </summary>
        /// <param name="input">The string to search.</param>
        /// <param name="addSpace">If true, adds a space 
        /// (" ") for each newline and carriage
        /// return found.</param>
        /// <returns>A string</returns>
        public static string RemoveNewLines(this string input,
           bool addSpace)
        {
            string replace = string.Empty;
            if (addSpace)
                replace = " ";

            string pattern = @"[\r|\n]";
            Regex regEx = new Regex(pattern,
               RegexOptions.IgnoreCase | RegexOptions.Multiline);

            return regEx.Replace(input, replace);
        }


        /// <summary>
        /// Converts a string to sentence case.
        /// </summary>
        /// <param name="input">The string to convert.</param>
        /// <returns>A string</returns>
        public static string SentenceCase(this string input)
        {
            if (input.Length < 1)
                return input;

            string sentence = input.ToLower();
            return sentence[0].ToString().ToUpper() +
               sentence.Substring(1);
        }

        /// <summary>
        /// Converts all spaces to HTML non-breaking spaces
        /// </summary>
        /// <param name="input">The string to convert.</param>
        /// <returns>A string</returns>
        public static string SpaceToNbsp(this string input)
        {
            string space = "&nbsp;";
            return input.Replace(" ", space);
        }

        /// <summary>
        /// Removes all HTML tags from the passed string
        /// </summary>
        /// <param name="input">The string whose 
        /// values should be replaced.</param>
        /// <returns>A string.</returns>
        public static string StripTags(this string input)
        {
            Regex stripTags = new Regex("<(.|\n)+?>");
            return stripTags.Replace(input, "");
        }

        /// <summary>
        /// Converts a string to title case.
        /// </summary>
        /// <param name="input">The string to convert.</param>
        /// <returns>A string.</returns>
        public static string TitleCase(this string input)
        {
            return input.TitleCase(true);
        }

        /// <summary>
        /// Converts a string to title case.
        /// </summary>
        /// <param name="input">The string to convert.</param>
        /// <param name="ignoreShortWords">If true, 
        /// does not capitalize words like
        /// "a", "is", "the", etc.</param>
        /// <returns>A string.</returns>
        public static string TitleCase(this string input,
           bool ignoreShortWords)
        {
            List<string> ignoreWords = null;
            if (ignoreShortWords)
            {
                //TODO: Add more ignore words?
                ignoreWords = new List<string>();
                ignoreWords.Add("a");
                ignoreWords.Add("is");
                ignoreWords.Add("was");
                ignoreWords.Add("the");
            }

            string[] tokens = input.Split(' ');
            StringBuilder sb = new StringBuilder(input.Length);
            foreach (string s in tokens)
            {
                if (ignoreShortWords == true
                    && s != tokens[0]
                    && ignoreWords.Contains(s.ToLower()))
                {
                    sb.Append(s + " ");
                }
                else
                {
                    sb.Append(s[0].ToString().ToUpper());
                    sb.Append(s.Substring(1).ToLower());
                    sb.Append(" ");
                }
            }

            return sb.ToString().Trim();
        }

        /// <summary>
        /// Removes multiple spaces between words
        /// </summary>
        /// <param name="input">The string to trim.</param>
        /// <returns>A string.</returns>
        public static string TrimIntraWords(this string input)
        {
            Regex regEx = new Regex(@"[\s]+");
            return regEx.Replace(input, " ");
        }

        /// <summary>
        /// Converts new line(\n) and carriage return(\r) symbols to
        /// HTML line breaks.
        /// </summary>
        /// <param name="input">The string to convert.</param>
        /// <returns>A string.</returns>
        public static string NewLineToBreak(this string input)
        {
            Regex regEx = new Regex(@"[\n|\r]+");
            return regEx.Replace(input, "<br />");
        }

        /// <summary>
        /// Wraps the passed string at the 
        /// at the next whitespace on or after the 
        /// total charCount has been reached
        /// for that line.  Uses the environment new line
        /// symbol for the break text.
        /// </summary>
        /// <param name="input">The string to wrap.</param>
        /// <param name="charCount">The number of characters 
        /// per line.</param>
        /// <returns>A string.</returns>
        public static string WordWrap(this string input, int charCount)
        {
            return input.WordWrap(charCount,
               false, Environment.NewLine);
        }

        /// <summary>
        /// Wraps the passed string at the total 
        /// number of characters (if cuttOff is true)
        /// or at the next whitespace (if cutOff is false).
        /// Uses the environment new line
        /// symbol for the break text.
        /// </summary>
        /// <param name="input">The string to wrap.</param>
        /// <param name="charCount">The number of characters 
        /// per line.</param>
        /// <param name="cutOff">If true, will break in 
        /// the middle of a word.</param>
        /// <returns>A string.</returns>
        public static string WordWrap(this string input,
           int charCount, bool cutOff)
        {
            return input.WordWrap(charCount,
               cutOff, Environment.NewLine);
        }

        /// <summary>
        /// Wraps the passed string at the total number 
        /// of characters (if cuttOff is true)
        /// or at the next whitespace (if cutOff is false).
        /// Uses the passed breakText
        /// for lineBreaks.
        /// </summary>
        /// <param name="input">The string to wrap.</param>
        /// <param name="charCount">The number of 
        /// characters per line.</param>
        /// <param name="cutOff">If true, will break in 
        /// the middle of a word.</param>
        /// <param name="breakText">The line break text to use.</param>
        /// <returns>A string.</returns>
        public static string WordWrap(this string input, int charCount,
           bool cutOff, string breakText)
        {
            StringBuilder sb = new StringBuilder(input.Length + 100);
            int counter = 0;

            if (cutOff)
            {
                while (counter < input.Length)
                {
                    if (input.Length > counter + charCount)
                    {
                        sb.Append(input.Substring(counter, charCount));
                        sb.Append(breakText);
                    }
                    else
                    {
                        sb.Append(input.Substring(counter));
                    }
                    counter += charCount;
                }
            }
            else
            {
                string[] strings = input.Split(' ');
                for (int i = 0; i < strings.Length; i++)
                {
                    // added one to represent the space.
                    counter += strings[i].Length + 1;
                    if (i != 0 && counter > charCount)
                    {
                        sb.Append(breakText);
                        counter = 0;
                    }

                    sb.Append(strings[i] + ' ');
                }
            }
            // to get rid of the extra space at the end.
            return sb.ToString().TrimEnd();
        }
        #endregion

        /// <summary>
        /// returns a new string containing only the alpha-numeric characters in the original
        /// </summary>
        public static string AlphaNumericOnly(string input)
        {
            StringBuilder sb = new StringBuilder();
            foreach (char ch in Check.NotNull(input))
            {
                if (Char.IsLetterOrDigit(ch))
                    sb.Append(ch);
            }

            return sb.ToString();
        }

        /// <summary>
        /// Parses the text to ensure that it is a valid file name and returns the resulting
        /// string with the following offending characters replace with '-': /\:*?"'&lt;>|
        /// Also removes any characters class as control characters, or anything below 32 space,
        /// this would include tab, backspace, newline, linefeed, etc.
        /// If provided null, this function returns null
        /// </summary>
        /// <param name="name">The text to parse</param>
        /// <returns>The text provided with only allowable characters</returns>
        public static string SafeFileName(string name)
        {
            if (name == null) return null;
            StringBuilder sbName = new StringBuilder();
            foreach (char ch in name)
            {
                if (ch >= ' ' && ch != '/' && ch != '\\' && ch != ':' &&
                        ch != '*' && ch != '?' && ch != '\'' && ch != '"' &&
                        ch != '<' && ch != '>' && ch != '|' && !Char.IsControl(ch))
                    sbName.Append(ch);
                else sbName.Append('-');
            }
            return sbName.ToString();
        }

        /// <summary>
        /// Splits the string on path characters ('/' and '\\') and passes each
        /// to SafeFileName(), then reconstructs the string using '\\' and
        /// removing any empty segments.
        /// If provided null, this function returns null, provided an empty
        /// string or just a path seperator '/' it will return String.Empty
        /// </summary>
        /// <param name="path">The text to parse</param>
        /// <returns>The text provided as a valid path</returns>
        public static string SafeFilePath(string path)
        {
            if (path == null) return null;

            StringBuilder sbPath = new StringBuilder();
            foreach (string part in path.Split('/', '\\'))
            {
                string name = SafeFileName(part);
                if (!String.IsNullOrEmpty(name))
                {
                    sbPath.Append(name);
                    sbPath.Append('\\');
                }
            }

            if (sbPath.Length == 0) return String.Empty;
            return sbPath.ToString(0, sbPath.Length - 1);
        }

        /// <summary>
        /// DO NOT EXPOSE THIS PRIVATE MEMEBER... Since the behavior of this can be changed this could have
        /// adverse effects in unrelated code.
        /// </summary>
        private static readonly Hack.Converters.StringConverter DefaultConverter = new Hack.Converters.StringConverter(true);

        /// <summary>
        /// Converts primitives to strings so that they can be reconstituted via TryParse
        /// </summary>
        public static string ToString<TYPE>(this TYPE value) { return DefaultConverter.ToString(value); }

        /// <summary>
        /// Converts primitives to strings so that they can be reconstituted via TryParse
        /// </summary>
        public static string ToString(this object value) { return DefaultConverter.ToString(value); }

        /// <summary>
        /// Reconstructs a type from a string that was previously obtained via StringUtils.ToString(T data)
        /// </summary>
        public static bool TryParse<TYPE>(this string input, out TYPE value) { return DefaultConverter.TryParse(input, out value); }

        /// <summary>
        /// Reconstructs a type from a string that was previously obtained via StringUtils.ToString(T data)
        /// </summary>
        public static bool TryParse(this string input, Type type, out object value) { return DefaultConverter.TryParse(input, type, out value); }

        /// <summary>
        /// Used for text-template transformation where a regex match is replaced in the input string.
        /// </summary>
        /// <param name="input">The text to perform the replacement upon</param>
        /// <param name="pattern">The regex used to perform the match</param>
        /// <param name="fnReplace">A delegate that selects the appropriate replacement text</param>
        /// <returns>The newly formed text after all replacements are made</returns>
        public static string Transform(this string input, Regex pattern, Converter<Match, string> fnReplace)
        {
            int currIx = 0;
            StringBuilder sb = new StringBuilder();

            foreach (Match match in pattern.Matches(input))
            {
                sb.Append(input, currIx, match.Index - currIx);
                string replace = fnReplace(match);
                sb.Append(replace);

                currIx = match.Index + match.Length;
            }

            sb.Append(input, currIx, input.Length - currIx);
            return sb.ToString();
        }

    }
    [Extension]
    public static class RegistryExtensions
    {
        public static IEnumerable<T> SubKeys<T>(this RegistryKey key, Func<string, RegistryKey, T> func)
        {
            string[] keyNames = key.GetSubKeyNames();
            foreach (var keyName in keyNames)
            {
                using (var k = key.OpenSubKey(keyName))
                    yield return func(keyName, k);
            }
        }
    }
    [Extension, OrginalAuthor(Url = "http://signum.codeplex.com")]
    public static class DictionaryExtensions
    {
        public static V TryGetC<K, V>(this IDictionary<K, V> dictionary, K key) where V : class
        {
            V result;
            if (dictionary.TryGetValue(key, out result))
                return result;
            return null;
        }

        public static V? TryGetS<K, V>(this IDictionary<K, V> dictionary, K key) where V : struct
        {
            V result;
            if (dictionary.TryGetValue(key, out result))
                return result;
            return null;
        }

        public static V? TryGetS<K, V>(this IDictionary<K, V?> dictionary, K key) where V : struct
        {
            V? result;
            if (dictionary.TryGetValue(key, out result))
                return result;
            return null;
        }

        public static V GetOrCreate<K, V>(this IDictionary<K, V> dictionary, K key) where V : new()
        {
            V result;
            if (!dictionary.TryGetValue(key, out result))
            {
                result = new V();
                dictionary.Add(key, result);
            }
            return result;
        }

        public static V GetOrCreate<K, V>(this IDictionary<K, V> dictionary, K key, V value)
        {
            V result;
            if (!dictionary.TryGetValue(key, out result))
            {
                result = value;
                dictionary.Add(key, result);
            }
            return result;
        }

        public static V GetOrCreate<K, V>(this IDictionary<K, V> dictionary, K key, Func<V> generator)
        {
            V result;
            if (!dictionary.TryGetValue(key, out result))
            {
                result = generator();
                dictionary.Add(key, result);
            }
            return result;
        }


        /// <param name="menssage"></param>
        public static V GetOrThrow<K, V>(this IDictionary<K, V> dictionary, K key, string menssage)
        {
            V result;
            if (!dictionary.TryGetValue(key, out result))
                throw new KeyNotFoundException(menssage.Formato(key));
            return result;
        }

        public static Dictionary<K2, V2> SelectDictionary<K1, V1, K2, V2>(this IDictionary<K1, V1> dictionary, Func<K1, K2> mapKey, Func<V1, V2> mapValue)
        {
            return dictionary.ToDictionary(p => mapKey(p.Key), p => mapValue(p.Value));
        }

        public static Dictionary<K2, V2> SelectDictionary<K1, V1, K2, V2>(this IDictionary<K1, V1> dictionary, Func<K1, K2> mapKey, Func<K1, V1, V2> mapValue)
        {
            return dictionary.ToDictionary(p => mapKey(p.Key), p => mapValue(p.Key, p.Value));
        }

        public static Dictionary<K, V> JumpDictionary<K, Z, V>(this IDictionary<K, Z> dictionary, IDictionary<Z, V> other)
        {
            return dictionary.SelectDictionary(k => k, z => other[z]);
        }

        public static Dictionary<K, V3> JoinDictionary<K, V1, V2, V3>(this IDictionary<K, V1> dic1, IDictionary<K, V2> dic2, Func<K, V1, V2, V3> mixer)
        {
            HashSet<K> set = new HashSet<K>();
            set.UnionWith(dic1.Keys);
            set.IntersectWith(dic2.Keys);

            return set.ToDictionary(k => k, k => mixer(k, dic1[k], dic2[k]));
        }

        public static void JoinDictionaryForeach<K, V1, V2>(this IDictionary<K, V1> dic1, IDictionary<K, V2> dic2, Action<K, V1, V2> action)
        {
            HashSet<K> set = new HashSet<K>();
            set.UnionWith(dic1.Keys);
            set.IntersectWith(dic2.Keys);

            set.ForEach(k => action(k, dic1[k], dic2[k]));
        }

        public static Dictionary<K, V3> OuterJoinDictionaryCC<K, V1, V2, V3>(this IDictionary<K, V1> dic1, IDictionary<K, V2> dic2, Func<K, V1, V2, V3> mixer)
            where V1 : class
            where V2 : class
        {
            HashSet<K> set = new HashSet<K>();
            set.UnionWith(dic1.Keys);
            set.UnionWith(dic2.Keys);

            return set.ToDictionary(k => k, k => mixer(k, dic1.TryGetC(k), dic2.TryGetC(k)));
        }

        public static Dictionary<K, V3> OuterJoinDictionarySC<K, V1, V2, V3>(this IDictionary<K, V1> dic1, IDictionary<K, V2> dic2, Func<K, V1?, V2, V3> mixer)
            where V1 : struct
            where V2 : class
        {
            HashSet<K> set = new HashSet<K>();
            set.UnionWith(dic1.Keys);
            set.UnionWith(dic2.Keys);

            return set.ToDictionary(k => k, k => mixer(k, dic1.TryGetS(k), dic2.TryGetC(k)));
        }

        public static Dictionary<K, V3> OuterJoinDictionarySC<K, V1, V2, V3>(this IDictionary<K, V1?> dic1, IDictionary<K, V2> dic2, Func<K, V1?, V2, V3> mixer)
            where V1 : struct
            where V2 : class
        {
            HashSet<K> set = new HashSet<K>();
            set.UnionWith(dic1.Keys);
            set.UnionWith(dic2.Keys);

            return set.ToDictionary(k => k, k => mixer(k, dic1.TryGetS(k), dic2.TryGetC(k)));
        }

        public static Dictionary<K, V3> OuterJoinDictionaryCS<K, V1, V2, V3>(this IDictionary<K, V1> dic1, IDictionary<K, V2> dic2, Func<K, V1, V2?, V3> mixer)
            where V1 : class
            where V2 : struct
        {
            HashSet<K> set = new HashSet<K>();
            set.UnionWith(dic1.Keys);
            set.UnionWith(dic2.Keys);

            return set.ToDictionary(k => k, k => mixer(k, dic1.TryGetC(k), dic2.TryGetS(k)));
        }

        public static Dictionary<K, V3> OuterJoinDictionaryCS<K, V1, V2, V3>(this IDictionary<K, V1> dic1, IDictionary<K, V2?> dic2, Func<K, V1, V2?, V3> mixer)
            where V1 : class
            where V2 : struct
        {
            HashSet<K> set = new HashSet<K>();
            set.UnionWith(dic1.Keys);
            set.UnionWith(dic2.Keys);

            return set.ToDictionary(k => k, k => mixer(k, dic1.TryGetC(k), dic2.TryGetS(k)));
        }

        public static Dictionary<K, V3> OuterJoinDictionarySS<K, V1, V2, V3>(this IDictionary<K, V1> dic1, IDictionary<K, V2> dic2, Func<K, V1?, V2?, V3> mixer)
            where V1 : struct
            where V2 : struct
        {
            HashSet<K> set = new HashSet<K>();
            set.UnionWith(dic1.Keys);
            set.UnionWith(dic2.Keys);

            return set.ToDictionary(k => k, k => mixer(k, dic1.TryGetS(k), dic2.TryGetS(k)));
        }

        public static Dictionary<K, V3> OuterJoinDictionarySS<K, V1, V2, V3>(this IDictionary<K, V1?> dic1, IDictionary<K, V2?> dic2, Func<K, V1?, V2?, V3> mixer)
            where V1 : struct
            where V2 : struct
        {
            HashSet<K> set = new HashSet<K>();
            set.UnionWith(dic1.Keys);
            set.UnionWith(dic2.Keys);

            return set.ToDictionary(k => k, k => mixer(k, dic1.TryGetS(k), dic2.TryGetS(k)));
        }

        public static void AddRange<K, V>(this IDictionary<K, V> dictionary, IEnumerable<K> keys, IEnumerable<V> values)
        {
            foreach (var item in keys.ZipStrict(values))
                dictionary.Add(item.First, item.Second);
        }

        public static void AddRange<K, V>(this IDictionary<K, V> dictionary, IDictionary<K, V> other)
        {
            foreach (var item in other)
            {
                dictionary.Add(item.Key, item.Value);
            }
        }

        public static void AddRange<K, V, A>(this IDictionary<K, V> dictionary, IEnumerable<A> collection, Func<A, K> getKey, Func<A, V> getValue)
        {
            foreach (var item in collection)
                dictionary.Add(getKey(item), getValue(item));
        }

        public static void SetRange<K, V>(this IDictionary<K, V> dictionary, IEnumerable<K> keys, IEnumerable<V> values)
        {
            foreach (var item in keys.ZipStrict(values))
                dictionary[item.First] = item.Second;
        }

        public static void SetRange<K, V>(this IDictionary<K, V> dictionary, Dictionary<K, V> other)
        {
            foreach (var item in other)
            {
                dictionary[item.Key] = item.Value;
            }
        }

        public static void SetRange<K, V, A>(this IDictionary<K, V> dictionary, IEnumerable<A> collection, Func<A, K> getKey, Func<A, V> getValue)
        {
            foreach (var item in collection)
                dictionary[getKey(item)] = getValue(item);
        }

        public static void RemoveRange<K, V>(this IDictionary<K, V> dictionary, IEnumerable<K> keys)
        {
            foreach (var k in keys)
                dictionary.Remove(k);
        }

        public static Dictionary<K, V> Union<K, V>(this IDictionary<K, V> dictionary, IDictionary<K, V> other)
        {
            Dictionary<K, V> result = new Dictionary<K, V>(dictionary);
            foreach (var kvp in other)
            {
                V value = result.GetOrCreate(kvp.Key, kvp.Value);
                Debug.Assert(EqualityComparer<V>.Default.Equals(value, kvp.Value));
            }
            return result;
        }

        public static Dictionary<K, V> Extract<K, V>(this IDictionary<K, V> dictionary, Func<K, bool> condition)
        {
            Dictionary<K, V> result = new Dictionary<K, V>();
            foreach (var key in dictionary.Keys.ToList())
            {
                if (condition(key))
                {
                    result.Add(key, dictionary[key]);
                    dictionary.Remove(key);
                }
            }
            return result;
        }

        public static Dictionary<K, V> Extract<K, V>(this IDictionary<K, V> dictionary, Func<K, V, bool> condition)
        {
            Dictionary<K, V> result = new Dictionary<K, V>();
            var aux = new Dictionary<K, V>(dictionary);
            foreach (var kvp in aux)
            {
                if (condition(kvp.Key, kvp.Value))
                {
                    result.Add(kvp.Key, kvp.Value);
                    dictionary.Remove(kvp.Key);
                }
            }
            return result;
        }


        public static V Extract<K, V>(this IDictionary<K, V> dictionary, K key)
        {
            V value = dictionary[key];
            dictionary.Remove(key);
            return value;
        }

        public static Dictionary<V, K> Inverse<K, V>(this IDictionary<K, V> dic)
        {
            return dic.ToDictionary(k => k.Value, k => k.Key);
        }
    }
    [Extension, OrginalAuthor(Url = "http://signum.codeplex.com")]
    public static class RandomExtensions
    {
        [ThreadStatic]
        static Random random;

        public static Random Current
        {
            get { return random ?? (random = new Random()); }
        }

        public static bool NextBool(this Random r)
        {
            return r.Next(2) == 1;
        }

        const string Lowercase = "abcdefgijkmnopqrstwxyz";
        const string Upercase = "ABCDEFGHJKLMNPQRSTWXYZ";


        public static char NextUppercase(this Random r)
        {
            return Upercase[r.Next(Upercase.Length)];
        }

        public static char NextLowercase(this Random r)
        {
            return Lowercase[r.Next(Lowercase.Length)];
        }

        public static char NextChar(this Random r)
        {
            string s = r.NextBool() ? Upercase : Lowercase;
            return s[r.Next(s.Length)];
        }

        public static string NextUppercaseString(this Random r, int length)
        {
            return new string(0.To(length).Select(i => r.NextUppercase()).ToArray());
        }

        public static string NextLowercaseString(this Random r, int length)
        {
            return new string(0.To(length).Select(i => r.NextLowercase()).ToArray());
        }

        public static string NextString(this Random r, int length)
        {
            return new string(0.To(length).Select(i => r.NextChar()).ToArray());
        }

        public static int NextAlphaColor(this Random r)
        {
            return Color(r.Next(256), r.Next(256), r.Next(256), r.Next(256));
        }

        public static int NextColor(this Random r)
        {
            return Color(255, r.Next(256), r.Next(256), r.Next(256));
        }

        public static int NextColor(this Random r, int minR, int maxR, int minG, int maxG, int minB, int maxB)
        {
            return Color(255, minR + r.Next(maxR - minR), minG + r.Next(maxG - minG), minB + r.Next(maxB - minB));
        }

        static int Color(int a, int r, int g, int b)
        {
            return a << 24 | r << 16 | g << 8 | b;
        }

        public static DateTime NextDateTime(this Random r, DateTime min, DateTime max)
        {
            return new DateTime(min.Ticks + r.NextLong(max.Ticks - min.Ticks));
        }

        public static long NextLong(this Random r, long max)
        {
            return (long)(r.NextDouble() * max);
        }

        public static long NextLong(this Random r, long min, long max)
        {
            return (long)(min + r.NextDouble() * (max - min));
        }

        public static T NextElement<T>(this Random r, params T[] elements)
        {
            return elements[r.Next(elements.Length)];
        }
    }
    [Extension]
    public static class StreamExtensions
    {
        const int BufferSize = 32768;

        public static byte[] ReadAllBytes(this Stream str)
        {
            using (MemoryStream ms = new MemoryStream())
            {
                str.CopyTo(ms);
                return ms.ToArray();
            }
        }

        public static void CopyTo(this Stream origin, Stream destiny)
        {
            byte[] buffer = new byte[BufferSize];
            while (true)
            {
                int read = origin.Read(buffer, 0, buffer.Length);
                if (read <= 0)
                    return;
                destiny.Write(buffer, 0, read);
            }
        }

        public static void WriteAllBytes(this Stream str, byte[] data)
        {
            str.Write(data, 0, data.Length);
        }
    }
    public static class TimeSpanExtensions
    {
        /// <summary>
        /// Converts <see cref="TimeSpan"/> to milliseconds as expected by
        /// most of the <see cref="System.Threading"/> API.
        /// </summary>

        public static int ToTimeout(this TimeSpan timeout)
        {
            return (int)timeout.TotalMilliseconds;
        }

        /// <summary>
        /// Converts <see cref="TimeSpan"/> to milliseconds as expected by
        /// most of the <see cref="System.Threading"/> API. If the the 
        /// <see cref="TimeSpan"/> value is <c>null</c> then the result is 
        /// same as <see cref="Timeout.Infinite"/>.
        /// </summary>

        public static int ToTimeout(this TimeSpan? timeout)
        {
            return timeout == null
                 ? Timeout.Infinite
                 : timeout.Value.ToTimeout();
        }
    }
    [Extension]
    public static class MathExtensions
    {
        public static int Round(this double d)
        {
            return (int)System.Math.Round(d);
        }

        public static double Bound(this double d, double lower, double upper)
        {
            if (d < lower)
                return lower;
            if (d > upper)
                return upper;
            return d;
        }
    }
    [Extension]
    public static class RectangleExtensions
    {
        public static IEnumerable<Rectangle> GetSubRectangles(this Rectangle rect, int width, int height)
        {
            var xSize = rect.Width / (double)width;
            var ySize = rect.Height / (double)height;
            return from y in 0.To(height)
                   from x in 0.To(width)
                   let r = CreateRectangle((int)(x * xSize), (int)(y * ySize), (int)((x + 1) * xSize), (int)((y + 1) * ySize))
                   where r.Height > 0 && r.Width > 0
                   select r;
        }

        public static Rectangle CreateRectangle(int x, int y, int nextX, int nextY)
        {
            return new Rectangle(x, y, nextX - x, nextY - y);
        }


    }
    [Extension]
    public static class ImageExtensions
    {
        public static IEnumerable<Color> GetPixels(this Bitmap image, Rectangle rect)
        {
            return from y in rect.Top.To(rect.Bottom)
                   from x in rect.Left.To(rect.Right)
                   select image.GetPixel(x, y);
        }

        public static double GetLuminosity(this Bitmap image, Rectangle rect)
        {
            return image.GetPixels(rect).Average(c => .3 * c.R + .59 * c.G + .11 * c.B) / 255;
        }

        public static Rectangle GetRectangle(this System.Drawing.Image image)
        {
            return new Rectangle(0, 0, image.Width, image.Height);
        }

        public static double Contrast(this double d, double contrast)
        {
            return (((d - .5) * contrast) + .5).Bound(0, 1);
        }
        public static byte[] ToBytes(this Bitmap original)
        {
            return (byte[])System.ComponentModel.TypeDescriptor.GetConverter(original).ConvertTo(original, typeof(byte[]));
        }
        public static Bitmap ToBitmap(this byte[] b)
        {
            using (var ms = new MemoryStream(b))
            { return (Bitmap)System.Drawing.Image.FromStream(ms); }
        }
        public static Bitmap Manipulate(this Bitmap original, ColorMatrix matrix)
        {
            //create a blank bitmap the same size as original
            var newBitmap = new Bitmap(original.Width, original.Height);

            //get a graphics object from the new image
            using (var g = Graphics.FromImage(newBitmap))
            {
                //create some image attributes
                var attributes = new ImageAttributes();

                //using the ColorMatrix from param
                //set the color matrix attribute
                attributes.SetColorMatrix(matrix);

                //draw the original image on the new image
                //using the grayscale color matrix
                g.DrawImage(original, new Rectangle(0, 0, original.Width, original.Height),
                   0, 0, original.Width, original.Height, GraphicsUnit.Pixel, attributes);


            } //dispose the Graphics object [AUTO(because -> using)]

            return original = newBitmap;
        }
        public static Bitmap Manipulate(this Bitmap original, int red, int green, int blue, int alpha)
        {
            return original = original.Manipulate(new ColorMatrix(new float[][]
                  {
                      new float[] {1, 0, 0, 0, 0},
                      new float[] {0, 1, 0, 0, 0},
                      new float[] {0, 0, 1, 0, 0},
                      new float[] {0, 0, 0, 1, 0},
// ReSharper disable PossibleLossOfFraction
                      new float[] {red/255, green/255, blue/255, alpha/255, 1}
// ReSharper restore PossibleLossOfFraction
                  }));
        }
        public static Bitmap GrayScale(this Bitmap original)
        {
            return original = original.Manipulate(new ColorMatrix(new float[][] 
                  {
                     new float[] {.3f, .3f, .3f, 0, 0},
                     new float[] {.59f, .59f, .59f, 0, 0},
                     new float[] {.11f, .11f, .11f, 0, 0},
                     new float[] {0, 0, 0, 1, 0},
                     new float[] {0, 0, 0, 0, 1}
                  }));
        }
        public static Bitmap Inverse(this Bitmap original)
        {
            return original = original.Manipulate(new ColorMatrix(new float[][]
                  {
                      new float[] {-1, 0, 0, 0, 0},
                      new float[] {0, -1, 0, 0, 0},
                      new float[] {0, 0, -1, 0, 0},
                      new float[] {0, 0, 0, 1, 0},
                      new float[] {1, 1, 1, 0, 1}
                  }));
        }
        public static Bitmap Netativate(this Bitmap original)
        {
            return original = original.Inverse();
        }
        public static Bitmap SepiaTone(this Bitmap original)
        {
            return original = original.Manipulate(new ColorMatrix(new float[][]
                  {
                    new float[] {.393f, .349f, .272f, 0, 0},
                    new float[] {.769f, .686f, .534f, 0, 0},
                    new float[] {.189f, .168f, .131f, 0, 0},
                    new float[] {0, 0, 0, 1, 0},
                    new float[] {0, 0, 0, 0, 1}
                  }));
        }

        public static Bitmap Add(this Bitmap original, ManipulationColors color, float amount)
        {
            float[][] colorMatrixElements =
            {
            new float[]{0.0f, 0.0f, 0.0f, 0.0f, 0.0f},
            new float[]{0.0f, 0.0f, 0.0f, 0.0f, 0.0f},
            new float[]{0.0f, 0.0f, 0.0f, 0.0f, 0.0f},
            new float[]{0.0f, 0.0f, 0.0f, 1.0f, 0.0f},
            new float[]{0.0f, 0.0f, 0.0f, 0.0f, 1.0f}
            };

            colorMatrixElements[(int)color][(int)color] = amount;
            return original = original.Manipulate(new ColorMatrix(colorMatrixElements));
        }

        public enum ManipulationColors : int
        {
            Red = 0,
            Green = 1,
            Blue = 2
        }
        [Description("ex: .50f for 50%")]
        public static Bitmap Translate(this Bitmap original, float intensity)
        {
            return original = original.Manipulate(new ColorMatrix(new float[][] 
                  {
                    new float[] {1, 0, 0, 0, 0},
                    new float[] {0, 1, 0, 0, 0},
                    new float[] {0, 0, 1, 0, 0},
                    new float[] {0, 0, 0, 1, 0},
                    new float[] {.0f, intensity, .0f, .0f, 1}
                  }));
        }
        public static Bitmap Binary(this Bitmap original, bool flag)
        {
            // GDI+ still lies to us - the return format is BGR, NOT RGB. 
            BitmapData bmData = original.LockBits(new Rectangle(0, 0, original.Width, original.Height),
                ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
            int stride = bmData.Stride; //the length of the line
            IntPtr Scan0 = bmData.Scan0;
            int Threshold = 220;
            unsafe
            {
                byte* p = (byte*)(void*)Scan0;

                int nOffset = stride - original.Width * 3;

                byte red, green, blue;
                byte binary;

                for (int y = 0; y < original.Height; ++y)
                {
                    for (int x = 0; x < original.Width; ++x)
                    {
                        blue = p[0];
                        green = p[1];
                        red = p[2];

                        binary = (byte)(.299 * red
                            + .587 * green
                            + .114 * blue);

                        if (binary < Threshold && flag)
                            p[0] = p[1] = p[2] = 0;
                        else
                            if (binary >= Threshold && flag)
                                p[0] = p[1] = p[2] = 255;
                            else
                                if (binary < Threshold && !flag)
                                    p[0] = p[1] = p[2] = 255;
                                else
                                    p[0] = p[1] = p[2] = 0;
                        p += 3;
                    }
                    p += nOffset;
                }

            }

            original.UnlockBits(bmData);
            return original;
        }
        [OrginalAuthor(Url = "http://www.nbdtech.com/Blog/archive/2008/04/27/Calculating-the-Perceived-Brightness-of-a-Color.aspx")]
        public static int Brightness(Color c)
        {
            return (int)SMath.Sqrt(
               c.R * c.R * .241 +
               c.G * c.G * .691 +
               c.B * c.B * .068);
        }

        public static Hack.Drawing.ColorHandler.RGB HSVtoRGB(this Hack.Drawing.ColorHandler.HSV HSV)
        {
            // HSV contains values scaled as in the color wheel:
            // that is, all from 0 to 255.

            // for ( this code to work, HSV.Hue needs
            // to be scaled from 0 to 360 (it//s the angle of the selected
            // point within the circle). HSV.Saturation and HSV.value must be
            // scaled to be between 0 and 1.

            double h;
            double s;
            double v;

            double r = 0;
            double g = 0;
            double b = 0;

            // Scale Hue to be between 0 and 360. Saturation
            // and value scale to be between 0 and 1.
            h = ((double)HSV.Hue / 255 * 360) % 360;
            s = (double)HSV.Saturation / 255;
            v = (double)HSV.value / 255;

            if (s == 0)
            {
                // If s is 0, all colors are the same.
                // This is some flavor of gray.
                r = v;
                g = v;
                b = v;
            }
            else
            {
                double p;
                double q;
                double t;

                double fractionalSector;
                int sectorNumber;
                double sectorPos;

                // The color wheel consists of 6 sectors.
                // Figure out which sector you//re in.
                sectorPos = h / 60;
                sectorNumber = (int)(SMath.Floor(sectorPos));

                // get the fractional part of the sector.
                // That is, how many degrees into the sector
                // are you?
                fractionalSector = sectorPos - sectorNumber;

                // Calculate values for the three axes
                // of the color.
                p = v * (1 - s);
                q = v * (1 - (s * fractionalSector));
                t = v * (1 - (s * (1 - fractionalSector)));

                // Assign the fractional colors to r, g, and b
                // based on the sector the angle is in.
                switch (sectorNumber)
                {
                    case 0:
                        r = v;
                        g = t;
                        b = p;
                        break;

                    case 1:
                        r = q;
                        g = v;
                        b = p;
                        break;

                    case 2:
                        r = p;
                        g = v;
                        b = t;
                        break;

                    case 3:
                        r = p;
                        g = q;
                        b = v;
                        break;

                    case 4:
                        r = t;
                        g = p;
                        b = v;
                        break;

                    case 5:
                        r = v;
                        g = p;
                        b = q;
                        break;
                }
            }
            // return an RGB structure, with values scaled
            // to be between 0 and 255.
            return new Hack.Drawing.ColorHandler.RGB((int)(r * 255), (int)(g * 255), (int)(b * 255));
        }

        private static float Px(int init, int end, int[] hist)
        {
            int sum = 0;
            int i;
            for (i = init; i <= end; i++)
                sum += hist[i];

            return (float)sum;
        }
        // function is used to compute the mean values in the equation (mu)
        private static float Mx(int init, int end, int[] hist)
        {
            int sum = 0;
            int i;
            for (i = init; i <= end; i++)
                sum += i * hist[i];

            return (float)sum;
        }
        unsafe private static void getHistogram(byte* p, int w, int h, int ws, int[] hist)
        {
            hist.Initialize();
            for (int i = 0; i < h; i++)
            {
                for (int j = 0; j < w * 3; j += 3)
                {
                    int index = i * ws + j;
                    hist[p[index]]++;
                }
            }
        }
        private static int findMax(float[] vec, int n)
        {
            float maxVec = 0;
            int idx = 0;
            int i;

            for (i = 1; i < n - 1; i++)
            {
                if (vec[i] > maxVec)
                {
                    maxVec = vec[i];
                    idx = i;
                }
            }
            return idx;
        }
        public static int OtsuThreshold(this Bitmap bmp)
        {
            byte t = 0;
            float[] vet = new float[256];
            int[] hist = new int[256];
            vet.Initialize();

            float p1, p2, p12;
            int k;

            BitmapData bmData = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height),
            ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb);
            unsafe
            {
                byte* p = (byte*)(void*)bmData.Scan0.ToPointer();

                getHistogram(p, bmp.Width, bmp.Height, bmData.Stride, hist);


                for (k = 1; k != 255; k++)
                {
                    p1 = Px(0, k, hist);
                    p2 = Px(k + 1, 255, hist);
                    p12 = p1 * p2;
                    if (p12 == 0)
                        p12 = 1;
                    float diff = (Mx(0, k, hist) * p2) - (Mx(k + 1, 255, hist) * p1);
                    vet[k] = (float)diff * diff / p12;

                }
            }
            bmp.UnlockBits(bmData);

            t = (byte)findMax(vet, 256);

            return t;
        }
        private static Bitmap _Threshold(this Bitmap bmp, int thresh)
        {
            BitmapData bmData = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height),
            ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb);
            unsafe
            {
                byte* p = (byte*)(void*)bmData.Scan0.ToPointer();
                int h = bmp.Height;
                int w = bmp.Width;
                int ws = bmData.Stride;

                for (int i = 0; i < h; i++)
                {
                    byte* row = &p[i * ws];
                    for (int j = 0; j < w * 3; j += 3)
                    {
                        row[j] = (byte)((row[j] > (byte)thresh) ? 255 : 0);
                        row[j + 1] = (byte)((row[j + 1] > (byte)thresh) ? 255 : 0);
                        row[j + 2] = (byte)((row[j + 2] > (byte)thresh) ? 255 : 0);
                    }
                }
            }
            bmp.UnlockBits(bmData);
            return bmp;
        }
        public static Bitmap Threshold(this Bitmap bmp)
        {
            Bitmap temp = (Bitmap)bmp.Clone();
            temp.GrayScale();
            int otsuThreshold = temp.OtsuThreshold();
            temp._Threshold(otsuThreshold);

            return temp;
        }


        public static long[] GetHistogram(this Bitmap picture)
        {
            long[] myHistogram = new long[256];

            for (int i = 0; i < picture.Size.Width; i++)
                for (int j = 0; j < picture.Size.Height; j++)
                {
                    System.Drawing.Color c = picture.GetPixel(i, j);

                    long Temp = 0;
                    Temp += c.R;
                    Temp += c.G;
                    Temp += c.B;

                    Temp = (int)Temp / 3;
                    myHistogram[Temp]++;
                }

            return myHistogram;
        }
        public static Bitmap GetHistogramImage(this Bitmap picture, Size size)
        {
            long myMaxValue;
            long[] myValues;

            float myYUnit; //this gives the vertical unit used to scale our values
            float myXUnit; //this gives the horizontal unit used to scale our values
            int myOffset = 20; //the offset, in pixels, from the control margins.
            myValues = picture.GetHistogram();



            Func<long[], long> getMaxim = delegate(long[] vals)
            {
                long max = 0;
                for (int i = 0; i < vals.Length; i++)
                {
                    if (vals[i] > max)
                        max = vals[i];
                }
                return max;
            };



            myMaxValue = getMaxim(myValues);

            myYUnit = (float)(size.Height - (2 * myOffset)) / myMaxValue;
            myXUnit = (float)(size.Width - (2 * myOffset)) / (myValues.Length - 1);


            Color myColor = Color.Black;
            Font myFont = new Font("Tahoma", 10);
            Bitmap bmf = new Bitmap(size.Width, size.Height);

            Graphics g = Graphics.FromImage(bmf);
            Pen myPen = new Pen(new SolidBrush(myColor), myXUnit);
            //The width of the pen is given by the XUnit for the control.
            for (int i = 0; i < myValues.Length; i++)
            {

                //We draw each line 
                g.DrawLine(myPen,
                    new PointF(myOffset + (i * myXUnit), size.Height - myOffset),
                    new PointF(myOffset + (i * myXUnit), size.Height - myOffset - myValues[i] * myYUnit));

                //We plot the coresponding index for the maximum value.
                if (myValues[i] == myMaxValue)
                {
                    SizeF mySize = g.MeasureString(i.ToString(), myFont);

                    g.DrawString(i.ToString(), myFont, new SolidBrush(myColor),
                        new PointF(myOffset + (i * myXUnit) - (mySize.Width / 2), size.Height - myFont.Height),
                        System.Drawing.StringFormat.GenericDefault);
                }
            }

            //We draw the indexes for 0 and for the length of the array beeing plotted
            g.DrawString("0", myFont, new SolidBrush(myColor), new PointF(myOffset, size.Height - myFont.Height), System.Drawing.StringFormat.GenericDefault);
            g.DrawString((myValues.Length - 1).ToString(), myFont,
                new SolidBrush(myColor),
                new PointF(myOffset + (myValues.Length * myXUnit) - g.MeasureString((myValues.Length - 1).ToString(), myFont).Width,
                size.Height - myFont.Height),
                System.Drawing.StringFormat.GenericDefault);

            //We draw a rectangle surrounding the control.
            g.DrawRectangle(new System.Drawing.Pen(new SolidBrush(Color.Black), 1), 0, 0, size.Width - 1, size.Height - 1);

            return bmf;
        }
    }
    [Extension]
    public static class ExceptionExtensions
    {
        public static ExceptionInfo ExceptionInfo(this Exception ex)
        {
            return new ExceptionInfo(ex);
        }
    }
    [Extension]
    public static class NullExtensions
    {

        public static bool WhenNotNull<T>(this T value, Action func) where T : class
        {
            if (value != null)
            {
                func();
                return true;
            }

            return false;
        }

        public static bool WhenNotNull<T>(this Nullable<T> value, Action func) where T : struct
        {
            if (value != null)
            {
                func();
                return true;
            }
            return false;
        }

        public static bool WhenNotNull<T>(this T value, Action<T> func) where T : class
        {
            if (value != null)
            {
                func(value);
                return true;
            }

            return false;
        }

        public static V WhenNotNull<T, V>(this T value, Func<V> func)
            where T : class
            where V : class
        {
            if (value != null)
            {
                return func();
            }

            return null;
        }

        public static V WhenNotNull<T, V>(this Nullable<T> value, Func<V> func)
            where T : struct
            where V : class
        {
            if (value != null)
            {
                return func();
            }

            return null;
        }

        public static TV WhenNotNullS<T, TV>(this Nullable<T> value, Func<TV> func)
            where T : struct
            where TV : struct
        {
            if (value != null)
            {
                return func();
            }

            return default(TV);
        }

        public static void ForNotNull<T>(this IEnumerable<T> list, Action<T> func) where T : class
        {
            if (list == null)
                return;

            foreach (var v in list)
            {
                if (v != null)
                    func(v);
            }
        }

        public static void ForNotNull<T>(this IEnumerable list, Action<T> func) where T : class
        {
            if (list == null)
                return;

            foreach (var v in list)
            {
                T castedValue = (T)v;
                func(castedValue);
            }
        }
    }
    [Extension]
    public static class ActionExtensions
    {
        static NumberFormatInfo myNumberFormat;

        static NumberFormatInfo NumberFormat
        {
            get
            {
                if (myNumberFormat == null)
                {
                    var local = new CultureInfo("en-us", false).NumberFormat;
                    local.NumberGroupSeparator = " "; // set space as thousand separator
                    myNumberFormat = local; // make a thread safe assignment with a fully initialized variable
                }
                return myNumberFormat;
            }
        }

        /// <summary>
        /// Execute the given function and print the elapsed time to the console.
        /// </summary>
        /// <param name="func">Function that returns the number of iterations.</param>
        /// <param name="format">Format string which can contain {runs} or {0},{time} or {1} and {frequency} or {2}.</param>
        public static void Profile(this Func<int> func, string format)
        {

            Stopwatch watch = Stopwatch.StartNew();
            int runs = func();  // Execute function and get number of iterations back
            watch.Stop();

            string replacedFormat = format.Replace("{runs}", "{3}")
                                          .Replace("{time}", "{4}")
                                          .Replace("{frequency}", "{5}");

            // get elapsed time back
            float sec = watch.ElapsedMilliseconds / 1000.0f;
            float frequency = runs / sec; // calculate frequency of the operation in question

            try
            {
                System.Console.WriteLine(replacedFormat,
                                    runs,  // {0} is the number of runs
                                    sec,   // {1} is the elapsed time as float
                                    frequency, // {2} is the call frequency as float
                                    runs.ToString("N0", NumberFormat),  // Expanded token {runs} is formatted with thousand separators
                                    sec.ToString("F2", NumberFormat),   // expanded token {time} is formatted as float in seconds with two digits precision
                                    frequency.ToString("N0", NumberFormat)); // expanded token {frequency} is formatted as float with thousands separators
            }
            catch (FormatException ex)
            {
                throw new FormatException(
                    String.Format("The input string format string did contain not an expected token like " +
                                  "{{runs}}/{{0}}, {{time}}/{{1}} or {{frequency}}/{{2}} or the format string " +
                                  "itself was invalid: \"{0}\"", format), ex);
            }
        }

        /// <summary>
        /// Execute the given function n-times and print the timing values (number of runs, elapsed time, call frequency)
        /// to the console window.
        /// </summary>
        /// <param name="func">Function to call in a for loop.</param>
        /// <param name="runs">Number of iterations.</param>
        /// <param name="format">Format string which can contain {runs} or {0},{time} or {1} and {frequency} or {2}.</param>
        public static void Profile(this Action func, int runs, string format)
        {
            Func<int> f = () =>
            {
                for (int i = 0; i < runs; i++)
                {
                    func();
                }
                return runs;
            };
            f.Profile(format);
        }

        /// <summary>
        /// Call a function in a for loop n-times. The first function call will be measured independently to measure
        /// first call effects.
        /// </summary>
        /// <param name="func">Function to call in a loop.</param>
        /// <param name="runs">Number of iterations.</param>
        /// <param name="formatFirst">Format string for first function call performance.</param>
        /// <param name="formatOther">Format string for subsequent function call performance.</param>
        /// <remarks>
        /// The format string can contain {runs} or {0},{time} or {1} and {frequency} or {2}.
        /// </remarks>
        public static void ProfileWithFirst(this Action func, int runs, string formatFirst, string formatOther)
        {
            func.Profile(1, formatFirst);
            func.Profile(runs - 1, formatOther);
        }
    }
    [Extension]
    public static class ReflectionExtensions
    {
        /// <summary>
        /// Invoke with added param [Object target]
        /// </summary>
        /// <param name="method"></param>
        /// <param name="target"></param>
        /// <param name="invokeArgs"></param>
        [DebuggerNonUserCode]
        [DebuggerStepThrough]
        public static void Invoke(this MethodInfo method, Object target, params Object[] invokeArgs)
        {
            try
            {
                method.Invoke(target, invokeArgs);
            }
            catch (TargetInvocationException te)
            {
                if (te.InnerException == null)
                    throw;
                var innerException = te.InnerException;

                var savestack = Delegate.CreateDelegate(typeof(ThreadStart), innerException, "InternalPreserveStackTrace", false, false) as ThreadStart;
                if (savestack != null) savestack();
                throw innerException;// -- now we can re-throw without trashing the stack
            }
        }
        public static Type UnNullify(this Type type)
        {
            return Nullable.GetUnderlyingType(type) ?? type;
        }

        public static Type Nullify(this Type type)
        {
            return type.IsNullable() ? type : typeof(Nullable<>).MakeGenericType(type);
        }

        public static bool IsNullable(this Type type)
        {
            return Nullable.GetUnderlyingType(type) != null;
        }

        public static Type ReturningType(this MemberInfo m)
        {
            return (m is PropertyInfo) ? ((PropertyInfo)m).PropertyType :
                (m is FieldInfo) ? ((FieldInfo)m).FieldType :
                (m is MethodInfo) ? ((MethodInfo)m).ReturnType :
                ((EventInfo)m).EventHandlerType;
        }


        public static T SingleAttribute<T>(this MemberInfo mi) where T : Attribute
        {
            return mi.GetCustomAttributes(typeof(T), false).Cast<T>().SingleOrDefault();
        }

        public static bool IsInstantiationOf(this Type type, Type genericType)
        {
            return type.IsGenericType && type.GetGenericTypeDefinition() == genericType;
        }

        public static bool FieldEquals<T>(this FieldInfo fi, Expression<Func<T, object>> lambdaToFiel)
        {
            return ReflectionTools.FieldEquals(ReflectionTools.GetFieldInfo(lambdaToFiel), fi);
        }

        public static bool PropertyEquals<T>(this PropertyInfo fi, Expression<Func<T, object>> lambdaToProperty)
        {
            return ReflectionTools.PropertyEquals(ReflectionTools.GetPropertyInfo(lambdaToProperty), fi);
        }
    }
}
